﻿using System;
using System.Collections.Generic;
using System.Data.SQLite;
using System.IO;
using System.Linq;
using CompactMapper.Orm.Contracts;
using CompactMapper.Orm.Queries;
using CompactMapper.Orm.UnitOfWork.Commands.Interfaces;

namespace CompactMapper.Orm.UnitOfWork.Mappings
{
    internal class TablesTree : Tree<Table>
    {
        private static Dictionary<String, Table> _tablesByName;
        private static readonly Dictionary<String, TablesTree> _tablesTreesByName = new Dictionary<string, TablesTree>();

        public TablesTree(IEnumerable<Table> allTables)
            : this()
        {
            _tablesByName = allTables.ToDictionary(table => table.Name);
        }

        public TablesTree()
            : this(RootMappingItem.Root)
        {
        }

        public TablesTree(Table node)
            : base(node)
        {
            var tableName = node.Name;
            if (_tablesTreesByName.ContainsKey(tableName))
                return;
            _tablesTreesByName.Add(tableName, this);
        }

        public TablesTree(IEnumerable<Tree<Table>> children)
            : this(RootMappingItem.Root, children)
        {
        }

        public TablesTree(Table node, IEnumerable<Tree<Table>> children)
            : base(node, children)
        {
        }

        public Table GetTable(Type type)
        {
            return GetTreeFor(type).Node;
        }

        public Table GetTable<T>()
        {
            return GetTable(typeof(T));
        }

        public Table GetTable(string tableName)
        {
            return _tablesByName[tableName];
        }

        internal Tree<Table> GetTreeFor(Type tableType)
        {
            if (tableType == typeof(Object))
                throw new InvalidOperationException("No table for type");
            if (_tablesTreesByName.ContainsKey(tableType.Name))
                return _tablesTreesByName[tableType.Name];
            return GetTreeFor(tableType.BaseType);
        }

        public override string ToString()
        {
            return Node.ToString();
        }

        #region Nested type: RootMappingItem

        internal class RootMappingItem : Table
        {
            private static readonly Type RootType = typeof(EmptyType);

            private static readonly ICreateTableCommand RooCreateTableCommandRoot = new EmptyCreateTableCommand();

            private static readonly IQueryCommand RootQueryCommand = new EmptyQueryCommand();

            private static readonly IInsertCommand RootInsertCommand = new EmptyInsertCommand();

            private static readonly IGetByKeyCommand RootUpdateCommand = new EmptyGetByKeyCommand();

            private static readonly IDeleteCommand RootDeleteCommand = new EmptyDeleteCommand();


            internal static RootMappingItem Root = new RootMappingItem(RootType)
                                                       {
                                                           CreateTableCommand = RooCreateTableCommandRoot,
                                                           QueryCommand = RootQueryCommand,
                                                           InsertCommand = RootInsertCommand,
                                                           GetByKeyCommand = RootUpdateCommand,
                                                           DeleteCommand = RootDeleteCommand
                                                       };

            public override bool AlreadyCreated
            {
                get { return false; }
                set { }
            }

            public RootMappingItem(Type tableClass)
                : base(tableClass)
            {
            }

            #region Nested type: EmptyCreateTableCommand

            private class EmptyCreateTableCommand : ICreateTableCommand
            {
                #region ICreateTableCommand Members

                public void Run(SQLiteConnection connection)
                {
                }

                public string TableName
                {
                    get { return null; }
                }

                public void OutputSql(TextWriter outputBuilder)
                {
                }

                #endregion
            }

            #endregion

            #region Nested type: EmptyDeleteCommand

            private class EmptyDeleteCommand : IDeleteCommand
            {
                #region IDeleteCommand Members

                public string TableName
                {
                    get { return null; }
                }

                public void Run(SQLiteConnection connection, IKey key)
                {
                }

                public void Run(SQLiteConnection connection)
                {
                }

                #endregion
            }

            #endregion

            #region Nested type: EmptyInsertCommand

            private class EmptyInsertCommand : IInsertCommand
            {
                #region IInsertCommand Members

                public string TableName
                {
                    get { return null; }
                }


                public Boolean Run(SQLiteConnection connection, IKeyedPersistent toPersist, string parentTableName,
                                IKey parentKey)
                {
                    return false;
                }

                #endregion
            }

            #endregion

            #region Nested type: EmptyQueryCommand

            private class EmptyQueryCommand : IQueryCommand
            {
                #region IQueryCommand Members

                public string TableName
                {
                    get { return null; }
                }

                public SQLiteDataReader Run(SQLiteConnection connection, Query query, TablesTree tablesTreeRoot)
                {
                    return null;
                }

                #endregion
            }

            #endregion

            #region Nested type: EmptyType

            private class EmptyType
            {
            }

            #endregion

            #region Nested type: EmptyGetByKeyCommand

            private class EmptyGetByKeyCommand : IGetByKeyCommand
            {
                #region IGetByKeyCommand Members

                public string TableName
                {
                    get { return null; }
                }

                public SQLiteDataReader Run(SQLiteConnection connection, IKey key)
                {
                    return null;
                }


                #endregion
            }

            #endregion
        }

        #endregion
    }
}